#!/usr/bin/env python3
"""
4_calculate_valuation.py
估值分析计算程序（健壮版）
"""

import pandas as pd
import numpy as np
import sys
import os

def calculate_price_percentile(current_price, historical_prices):
    """计算价格历史分位"""
    if len(historical_prices) == 0:
        return np.nan
    return (historical_prices <= current_price).mean() * 100

def calculate_distance_from_ma(current_price, ma_price):
    """计算偏离均线程度"""
    if ma_price == 0 or np.isnan(ma_price):
        return np.nan
    return (current_price - ma_price) / ma_price * 100

def calculate_relative_strength(price_series, benchmark_series):
    """计算相对强弱"""
    if len(price_series) == 0 or len(benchmark_series) == 0:
        return np.nan
    return (price_series.pct_change().cumsum().iloc[-1] -
            benchmark_series.pct_change().cumsum().iloc[-1]) * 100

def calculate_volatility_percentile(current_vol, historical_vol):
    """计算波动率分位"""
    if len(historical_vol) == 0 or np.isnan(current_vol):
        return np.nan
    return (historical_vol <= current_vol).mean() * 100

def calculate_momentum_score(price_series, window=20):
    """计算动量得分"""
    if len(price_series) < window:
        return np.nan
    returns = price_series.pct_change(window)
    return returns.iloc[-1] * 100

def calculate_trend_strength(price_series, window=20):
    """计算趋势强度"""
    if len(price_series) < window:
        return np.nan
    
    x = np.arange(window)
    y = price_series.iloc[-window:].values
    
    # 避免全零或异常
    if y.mean() == 0:
        return np.nan
    
    slope, _ = np.polyfit(x, y, 1)  # 线性回归斜率
    normalized_slope = (slope * window) / y.mean() * 100
    return normalized_slope

def calculate_support_resistance(price_series, window=20):
    """计算支撑阻力位"""
    if len(price_series) < window:
        return np.nan, np.nan, np.nan
    
    recent_data = price_series.iloc[-window:]
    support = recent_data.min()
    resistance = recent_data.max()
    current_price = price_series.iloc[-1]
    
    if resistance == support:
        position = np.nan
    else:
        position = (current_price - support) / (resistance - support) * 100
    
    return support, resistance, position

def calculate_fibonacci_levels(price_series):
    """计算斐波那契回撤位"""
    if len(price_series) < 50:
        return {}
    
    max_price = price_series.max()
    min_price = price_series.min()
    diff = max_price - min_price
    if diff == 0:
        return {}
    
    current_price = price_series.iloc[-1]
    
    return {
        '0': max_price,
        '23.6': max_price - 0.236 * diff,
        '38.2': max_price - 0.382 * diff,
        '50': max_price - 0.5 * diff,
        '61.8': max_price - 0.618 * diff,
        '78.6': max_price - 0.786 * diff,
        '100': min_price,
        'current_position': (max_price - current_price) / diff * 100
    }

def calculate_seasonality(price_series):
    """计算季节性因子"""
    if len(price_series) < 30:
        return np.nan
    
    df = pd.DataFrame({'date': price_series.index, 'price': price_series.values})
    df['month'] = pd.to_datetime(df['date']).dt.month
    df['return'] = df['price'].pct_change()
    
    monthly_returns = df.groupby('month')['return'].mean()
    
    current_month = pd.to_datetime('today').month
    if current_month in monthly_returns.index:
        return monthly_returns.loc[current_month] * 100
    else:
        return np.nan

def calculate_valuation_metrics():
    """计算所有估值指标"""
    
    # 读取输入数据
    input_file = '../csv_output/level3_risk_return.csv'
    if not os.path.exists(input_file):
        print("❌ level3_risk_return.csv 不存在", file=sys.stderr)
        sys.exit(1)
    
    df = pd.read_csv(input_file)
    df['date'] = pd.to_datetime(df['date'])
    df = df.sort_values('date').reset_index(drop=True)
    
    # 基础数据
    close = df['close']
    if len(close) == 0:
        print("❌ 数据为空", file=sys.stderr)
        sys.exit(1)
    
    current_price = close.iloc[-1]
    
    # 价格分位（基于1年历史）
    lookback_days = min(252, len(close))
    price_percentile = calculate_price_percentile(current_price, close.iloc[-lookback_days:])
    
    # 均线偏离
    ma20 = close.rolling(20).mean().iloc[-1]
    distance_ma20 = calculate_distance_from_ma(current_price, ma20)
    ma60 = close.rolling(60).mean().iloc[-1]
    distance_ma60 = calculate_distance_from_ma(current_price, ma60)
    
    # 动量指标
    momentum_20d = calculate_momentum_score(close, 20)
    momentum_60d = calculate_momentum_score(close, 60)
    
    # 趋势强度
    trend_strength_20d = calculate_trend_strength(close, 20)
    trend_strength_60d = calculate_trend_strength(close, 60)
    
    # 支撑阻力
    support, resistance, position = calculate_support_resistance(close)
    
    # 斐波那契水平
    fib_levels = calculate_fibonacci_levels(close)
    
    # 季节性
    seasonality_score = calculate_seasonality(close)
    
    # 波动率分位
    if 'volatility_20d' in df.columns:
        current_vol = df['volatility_20d'].iloc[-1]
        vol_percentile = calculate_volatility_percentile(current_vol, df['volatility_20d'].dropna())
    else:
        vol_percentile = np.nan
    
    # 估值状态
    if pd.isna(price_percentile):
        valuation_status = '未知'
    elif price_percentile < 30:
        valuation_status = '低估'
    elif price_percentile < 70:
        valuation_status = '合理'
    else:
        valuation_status = '高估'
    
    # 均线位置
    if pd.isna(distance_ma20):
        ma_position = '未知'
    elif abs(distance_ma20) < 5:
        ma_position = '中性'
    elif distance_ma20 < -5:
        ma_position = '超卖'
    else:
        ma_position = '超买'
    
    # 添加到 DataFrame（避免覆盖整个 df，用 assign 更安全）
    df = df.assign(
        price_percentile=price_percentile,
        distance_ma20=distance_ma20,
        distance_ma60=distance_ma60,
        momentum_20d=momentum_20d,
        momentum_60d=momentum_60d,
        trend_strength_20d=trend_strength_20d,
        trend_strength_60d=trend_strength_60d,
        support_level=support,
        resistance_level=resistance,
        position_in_range=position,
        volatility_percentile=vol_percentile,
        valuation_status=valuation_status,
        ma_position=ma_position,
        seasonality_score=seasonality_score
    )
    
    # 添加斐波那契水平
    for key, value in fib_levels.items():
        df[f'fib_{key}'] = value
    
    # 综合估值评分（0-100）
    price_score = 0 if pd.isna(price_percentile) else max(0, 100 - price_percentile)
    distance_score = 0 if pd.isna(distance_ma20) else max(0, 100 - abs(distance_ma20))
    trend_score = 0 if pd.isna(trend_strength_20d) else min(100, abs(trend_strength_20d) * 2)
    
    df['valuation_score'] = price_score * 0.4 + distance_score * 0.3 + trend_score * 0.3
    
    # 保存结果
    df.to_csv('../csv_output/level4_valuation.csv', index=False)
    
    # 打印摘要
    print("✅ 估值分析计算完成")
    print(f"💰 当前价格分位: {price_percentile:.1f}%")
    print(f"📊 估值状态: {valuation_status}")
    print(f"🎯 偏离MA20: {distance_ma20:.2f}%")
    print(f"📈 20日动量: {momentum_20d:.2f}%")
    print(f"🔍 支撑/阻力: {support:.2f}/{resistance:.2f}")
    print(f"📍 当前位置: {position:.1f}%")

def main():
    if not os.path.exists('../csv_output/level3_risk_return.csv'):
        print("❌ 请先运行3_calculate_risk.py", file=sys.stderr)
        sys.exit(1)
    
    calculate_valuation_metrics()
    print("✅ level4_valuation.csv 已生成")

if __name__ == "__main__":
    main()

